﻿Imports System.Drawing.Drawing2D
Imports System.Reflection
Imports System.Runtime.InteropServices


Public Class FrmColorPicker
    Private colorChartImg As Bitmap = New Bitmap(1, 1)
    Private colorBrightnessImg As Bitmap = New Bitmap(1, 1)
    Private image As Bitmap = New Bitmap(1, 1)
    Private cursorPos As Point = New Point(20, 20)
    Private mousePos As Point = New Point(-1, -1)
    Private mouseIsDown As Boolean = False
    Private brightness As Integer = 129
    Private primaryColor As Color
    Private _Value As Color
    Private ColorList As New List(Of Color)
    Private loaded As Boolean = False

    <DllImport("user32.dll")> _
    Private Shared Function GetDC(hwnd As IntPtr) As IntPtr
    End Function

    <DllImport("user32.dll")> _
    Private Shared Function ReleaseDC(hwnd As IntPtr, hdc As IntPtr) As Int32
    End Function

    <DllImport("gdi32.dll")> _
    Private Shared Function GetPixel(hdc As IntPtr, nXPos As Integer, nYPos As Integer) As UInteger
    End Function

    Public Shared Function GetPixelColor(x As Integer, y As Integer) As System.Drawing.Color
        Dim hdc As IntPtr = GetDC(IntPtr.Zero)
        Dim pixel As UInteger = GetPixel(hdc, x, y)
        ReleaseDC(IntPtr.Zero, hdc)
        Dim color__1 As Color = Color.FromArgb(CInt(pixel And &HFF), CInt(pixel And &HFF00) >> 8, CInt(pixel And &HFF0000) >> 16)
        Return color__1
    End Function

    Public Property Value() As Color
        Get
            Return _Value
        End Get
        Set(ByVal value As Color)
            _Value = value
        End Set
    End Property

    Private Sub FrmColorPicker_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

        colorChartImg = New Bitmap(Pb_ColorChart.Width, Pb_ColorChart.Height)
        colorBrightnessImg = New Bitmap(Pb_ColorBrightness.Width, Pb_ColorBrightness.Height)
        image = New Bitmap(Pb_ColorChart.Width, Pb_ColorChart.Height)
        Dessiner(True)


        Dim colType As Type = GetType(System.Drawing.Color)
        Dim pInfo() As PropertyInfo = colType.GetProperties(BindingFlags.Static & BindingFlags.DeclaredOnly & BindingFlags.Public)

        If Not loaded Then
            For Each col As PropertyInfo In pInfo
                Cb_Color.Items.Add(SpacesBeforeCaps(col.Name))
                ColorList.Add(Color.FromName(col.Name))
            Next
            loaded = True
        End If
        If Not Value.IsEmpty Then
            'Console.WriteLine("col = " + Value.R.ToString + " " + Value.G.ToString + " " + Value.B.ToString)
            SetColor(Value)
        Else
            SelectColor()
        End If
        Pb_ColorPreview.BackColor = Value


    End Sub

    Private Sub Dessiner(Optional drawChart As Boolean = False)
        If drawChart Then
            Using g As Graphics = Graphics.FromImage(colorChartImg)

                Dim rect As New Rectangle(0, 0, 260, 260)
                Dim lgb As New LinearGradientBrush(rect, SystemColors.ControlDark, SystemColors.ControlLightLight, 45.0F)
                g.FillRectangle(lgb, rect)
                g.FillRectangle(Brushes.White, 2, 2, 256, 256)

                For y As Integer = 0 To 255
                    For x As Integer = 0 To 255
                        g.FillRectangle(New SolidBrush(PosToColor(New Point(x, y), New Size(256, 256))), x + 2, y + 2, 1, 1)
                    Next
                Next

            End Using
        End If

        Using g As Graphics = Graphics.FromImage(image)
            g.Clear(SystemColors.Control)
            g.DrawImage(colorChartImg, 0, 0)
            g.DrawEllipse(Pens.Black, cursorPos.X - 6, cursorPos.Y - 6, 10, 10)
            If mousePos <> New Point(-1, -1) Then
                g.DrawEllipse(Pens.Black, mousePos.X - 8, mousePos.Y - 8, 14, 14)
                g.DrawEllipse(Pens.White, mousePos.X - 7, mousePos.Y - 7, 12, 12)
            End If

        End Using
        Using g As Graphics = Pb_ColorChart.CreateGraphics()
            g.DrawImageUnscaled(image, 0, 0)
        End Using
        'Pb_ColorChart.BackgroundImage = image
    End Sub

    Private Sub DessinerBrightness()
        Using g As Graphics = Graphics.FromImage(colorBrightnessImg)
            'g.CompositingQuality = CompositingQuality.HighQuality
            'g.InterpolationMode = InterpolationMode.Bicubic
            g.Clear(SystemColors.Control)
            Dim rectBorder As New Rectangle(4, 4, 28, 259)
            Dim rectFill As New Rectangle(6, 6, 24, 254)

            Dim lgbBorder As New LinearGradientBrush(rectBorder, SystemColors.ControlDark, SystemColors.ControlLightLight, 15.0F)
            Dim lgbFill As New LinearGradientBrush(rectFill, Color.Black, Color.Black, 90, False)

            Dim color_blend As New ColorBlend
            color_blend.Colors = New Color() {Color.White, primaryColor, Color.Black}
            color_blend.Positions = New Single() {0.0F, 0.5F, 1.0F}
            lgbFill.InterpolationColors = color_blend

            g.FillRectangle(lgbBorder, rectBorder)
            g.FillRectangle(lgbFill, rectFill)
            g.FillRectangle(Brushes.Black, 6, 259, 24, 2)
            g.FillRectangle(Brushes.White, 6, 6, 24, 1)
            g.DrawImageUnscaled(My.Resources.SliderArrow, 0, brightness)
            Dim img2 = My.Resources.SliderArrow
            img2.RotateFlip(RotateFlipType.RotateNoneFlipX)
            g.DrawImageUnscaled(img2, 25, brightness)

        End Using

        Using g As Graphics = Pb_ColorBrightness.CreateGraphics()
            g.DrawImageUnscaled(colorBrightnessImg, 0, 0)
        End Using
        'Pb_ColorBrightness.BackgroundImage = colorBrightnessImg
    End Sub

    Private Function PosToColor(ByVal pt As Point, ByVal sz As Size) As Color
        Dim col As Color
        'r v b r
        Dim sectionW As Double = Convert.ToDouble(sz.Width) / 6
        pt.X = Math.Min(pt.X, sz.Width)
        Select Case Math.Floor(pt.X / sectionW)
            Case 0
                col = Color.FromArgb(255, 255 * (pt.X Mod sectionW) / sectionW, 0)
            Case 1
                col = Color.FromArgb(255 - 255 * (pt.X Mod sectionW) / sectionW, 255, 0)
            Case 2
                col = Color.FromArgb(0, 255, 255 * (pt.X Mod sectionW) / sectionW)
            Case 3
                col = Color.FromArgb(0, 255 - 255 * (pt.X Mod sectionW) / sectionW, 255)
            Case 4
                col = Color.FromArgb(255 * (pt.X Mod sectionW) / sectionW, 0, 255)
            Case 5
                col = Color.FromArgb(255, 0, 255 - 255 * (pt.X Mod sectionW) / sectionW)
        End Select

        col = Color.FromArgb(Math.Max(col.R - ((col.R - 127) * pt.Y) / sz.Height, 0), _
                             Math.Max(col.G - ((col.G - 127) * pt.Y) / sz.Height, 0), _
                             Math.Max(col.B - ((col.B - 127) * pt.Y) / sz.Height, 0))
        Return col
    End Function

    Private Sub Pb_ColorChart_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles Pb_ColorChart.Paint
        Pb_ColorChart.BackgroundImage = image
    End Sub

    Private Sub Pb_ColorChart_MouseMove(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles Pb_ColorChart.MouseMove
        mousePos = e.Location
        If mouseIsDown Then
            cursorPos = New Point(Math.Min(Math.Max(mousePos.X, 2), 257), Math.Min(Math.Max(mousePos.Y, 2), 257))
            SelectColor()
        End If
        Dessiner()
    End Sub

    Private Sub Pb_ColorChart_MouseLeave(sender As System.Object, e As System.EventArgs) Handles Pb_ColorChart.MouseLeave
        mousePos = New Point(-1, -1)
        Dessiner()
        Cursor.Show()
    End Sub

    Private Sub Pb_ColorChart_MouseEnter(sender As System.Object, e As System.EventArgs) Handles Pb_ColorChart.MouseEnter
        Cursor.Hide()
    End Sub

    Private Sub Pb_ColorChart_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles Pb_ColorChart.MouseDown
        mouseIsDown = True
        cursorPos = New Point(Math.Min(Math.Max(mousePos.X, 2), 257), Math.Min(Math.Max(mousePos.Y, 2), 257))
        SelectColor()
        Dessiner()
        Cursor.Clip = Me.RectangleToScreen(Pb_ColorChart.Bounds)
    End Sub

    Private Sub Pb_ColorChart_MouseUp(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles Pb_ColorChart.MouseUp
        mouseIsDown = False
        Cursor.Clip = New Rectangle(0, 0, 0, 0)
    End Sub

    Private Sub SelectColor()

        primaryColor = PosToColor(New Point(cursorPos.X - 2, cursorPos.Y - 2), New Size(256, 255))
        DessinerBrightness()
        Value = colorBrightnessImg.GetPixel(20, brightness + 5)
        'Value = primaryColor
        Using g As Graphics = Pb_ColorPreview.CreateGraphics()
            g.FillRectangle(New SolidBrush(Value), 0, 0, Pb_ColorPreview.Bounds.Width, Pb_ColorPreview.Height)
        End Using
        If ColorList.Where(Function(c) ColorAreNear(c, Value, 15)).Count = 1 Then
            Cb_Color.SelectedItem = SpacesBeforeCaps(ColorList.First(Function(c) ColorAreNear(c, Value, 15)).Name)
        End If
    End Sub

    Private Function ColorAreNear(ByVal col1 As Color, ByVal col2 As Color, Optional range As Integer = 5) As Boolean
        Return (col1.R >= col2.R - range And col1.R <= col2.R + range And _
                col1.G >= col2.G - range And col1.G <= col2.G + range And _
                col1.B >= col2.B - range And col1.B <= col2.B + range)
    End Function

    Private Sub Pb_ColorBrightness_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles Pb_ColorBrightness.Paint
        Pb_ColorBrightness.BackgroundImage = colorBrightnessImg
    End Sub

    Private Sub Pb_ColorBrightness_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles Pb_ColorBrightness.MouseDown
        brightness = Math.Min(259, Math.Max(5, e.Y - 2)) - 4
        mouseIsDown = True
        SelectColor()
    End Sub

    Private Sub Pb_ColorBrightness_MouseMove(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles Pb_ColorBrightness.MouseMove
        If mouseIsDown Then
            brightness = Math.Min(259, Math.Max(5, e.Y - 2)) - 4
            SelectColor()
        End If
    End Sub

    Private Sub Pb_ColorBrightness_MouseUp(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles Pb_ColorBrightness.MouseUp
        mouseIsDown = False
    End Sub

    Public Sub SetColor(ByVal col)
        Dim oldCol As Color = col
        cursorPos = New Point(RGBHSL.RGB_to_HSL(col).H * 256 + 2, 256 - RGBHSL.RGB_to_HSL(col).S * 256 + 2)
        brightness = 254 - RGBHSL.RGB_to_HSL(col).L * 254 + 1
        Dessiner()
        SelectColor()
        Value = col
        'Console.WriteLine("col = " + Value.R.ToString + " " + Value.G.ToString + " " + Value.B.ToString)

        If ColorList.Where(Function(c) ColorAreNear(c, Value, 2)).Count = 1 Then
            Cb_Color.SelectedItem = SpacesBeforeCaps(ColorList.First(Function(c) ColorAreNear(c, Value)).Name)
        End If
    End Sub

    Private Sub ComboBox1_DrawItem(sender As System.Object, e As System.Windows.Forms.DrawItemEventArgs) Handles Cb_Color.DrawItem

        Dim rect As Rectangle = e.Bounds
        If e.Index >= 0 Then

            Using g As Graphics = e.Graphics
                g.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAliasGridFit
                Dim nom As String = Cb_Color.Items(e.Index).ToString()
                Dim f As Font = Cb_Color.Font
                Dim c As Color = ColorList(e.Index)
                Dim b As New SolidBrush(c)
                g.DrawString(nom, f, Brushes.Black, rect.X, rect.Top)
                g.FillRectangle(b, rect.X + rect.Width - rect.Height - 2, rect.Y + 2, rect.Height, rect.Height - 4)

            End Using
        End If
    End Sub

    Private Sub Cb_Color_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles Cb_Color.SelectedIndexChanged
        If Not mouseIsDown Then
            SetColor(ColorList(Cb_Color.SelectedIndex))
        End If

    End Sub

    Private Sub FrmColorPicker_KeyPress(sender As System.Object, e As System.Windows.Forms.KeyPressEventArgs) Handles MyBase.KeyPress

        If e.KeyChar = Chr(99) Or e.KeyChar = Chr(67) Then

            SetColor(GetPixelColor(Cursor.Position.X, Cursor.Position.Y))
        End If
    End Sub
End Class